#include "copyright.h"
#include "system.h"
#ifdef CHANGED
#include "synch.h"
#endif

#ifdef CHANGED


/*
 *part 2 code starts here///
 */


/*monitor variables and shared information
 *setup for dynamic allocation
 */
/*
 *shared data        //
 */

/*pointer to array of ints to represent visitors in the car*/
const int numberOfCars = 1;
const int numberOfLimos = 1;
const int numberOfValets = 1;

int passengers[numberOfCars];
int limoPassengers[numberOfLimos];

/*pointer to array of ints to represent visitors out of the car*/
int outOfCar[numberOfCars];
int limoOutOfCar[numberOfLimos];

/*integer to keep track of number of cars in line*/
int inLine = 0;
int limoLine = 0;

/*integer to keep track of how many people are in line to get the tickets taken*/
int ticketLineCount = 0;
int inMuseum = 0;
int driverWaiting =0;
int limoWaiting =0;
int onBench = 0;
int working = 2;


/*
 *Locks              //
 */

/*array of lock pointers with one lock for each car based on the index*/
int carLock[numberOfCars];
int limoLock[numberOfLimos];

int parkingLock = (int)CreateLock();
int lineLock = (int)CreateLock();
int breakLock = (int)CreateLock() ;

/*
 *condition variables
 */


int driverWaitingCV[numberOfCars];
int visitorExit[numberOfCars];
int canLeave[numberOfCars];
int hasKeys[numberOfCars];
int hasToken[numberOfCars];
int leaveToken[numberOfCars];
int readyToLeave[numberOfCars];
int waitToLeave[numberOfCars];
int waitExit[numberOfCars];
int waitCarLeaving[numberOfCars];
int Tip[numberOfCars]


int leaving = (int)CreateCondition();
int readyToPark = (int)CreateCondition();


/*limo CV's*/
int limoWaitingCV[numberOfLimos];
int visitorLimoExit[numberOfLimos];
int limoCanLeave[numberOfLimos];
int limoHasKeys[numberOfLimos];
int limoHasToken[numberOfLimos];
int limoLeaveToken[numberOfLimos];
int limoReadyToLeave[numberOfLimos];
int limoWaitToLeave[numberOfLimos];
int limoWaitExit[numberOfLimos];
int waitLimoLeaving[numberOfLimos];
int limoTip[numberOfLimos];

int limoLeaving = (int)CreateCondition();
int limoReadyToPark = (int)CreateCondition();

int waitForCars = (int)CreateCondition();
int waitOnCustomers = (int)CreateCondition();
int ticketLine = (int)CreateCondition();
int managerWaiting = (int)CreateCondition();
int backRoom = (int)CreateCondition();
int waitForBreak = (int)CreateCondition();

int carnumbersArrive = (int)CreateList();
int carnumbersLeave = (int)CreateList();
int limoListToPark = (int)CreateList();
int limoListToLeave = (int)CreateList();

/*for dynamic visitor creation*/
struct visInfo{
  char* name;
  int carNum;
  int limoNum;
  int limotrue; /*1 means vis on limo, 0 means vis on car*/
  int visNum;
};



/*go to museum function*/

void goToMuseum(){
  int i;
  /*get a random number between 50 and 100*/
  int randomNum = rand()%101 + 50;
  
  /*simulate time inside the museum*/
  for(i = randomNum; i>0; i--){
    Yield();
  }
}


int sum = limoWaiting + limoLine + inLine + driverWaiting;


/*
 * Driver Code
 */


/*Function Car Arrive to the Museum*/
void driveInMuseum(int number, char* name){
  int carNum = number;


  /*code for arriving at museum and getting in line
   *print message to show they have arrived*/
  Write(name, 3, ConsoleOutput);
  Write(" ",1,ConsoleOutput);
  PrintInt(carNum);
  Write (" has arrived at the Museum", 26, ConsoleOutput);

  /*  cout<<name<<" "<<carNum<<" has arrived at the museum"<<endl;*/

  /*atomic operation
   *get parking lock*/
  Acquire(parkingLock);

  Write(name, 3, ConsoleOutput);
  Write(" ",1,ConsoleOutput);
  PrintInt(carNum);
  Write (" is getting in line to be parked", 30, ConsoleOutput);  


  /*increment inLine count*/
  inLine++;
  AddtoList(carNum,carnumbersArrive);

  Write(name, 3, ConsoleOutput);
  Write(" ",1,ConsoleOutput);
  PrintInt(carNum);
  Write (" is in line to be parked", 23, ConsoleOutput);  

  Signal(parkingLock,waitForCars);
  Wait(parkingLock,readyToPark);
  Release(parkingLock);

}


void limoDriveInMuseum(int number, char* name){

  int carNum = number;

  /*code for arriving at museum and getting in line
   *print message to show they have arrived
   */

  Write(name, 3, ConsoleOutput);
  Write(" ",1,ConsoleOutput);
  PrintInt(carNum);
  Write (" has arrived at the Museum", 26, ConsoleOutput);  

  /*atomic operation
   *get parking lock
   */
  Acquire(parkingLock);

  //print message to get in line
  
  Write(name, 3, ConsoleOutput);
  Write(" ",1,ConsoleOutput);
  PrintInt(carNum);
  Write (" is getting in line to be parked", 26, ConsoleOutput); 

  /*increment inLine count*/
  limoLine++;

  AddtoList(carNum,limoListToPark);

  Write(name, 3, ConsoleOutput);
  Write(" ",1,ConsoleOutput);
  PrintInt(carNum);
  Write (" is in line to be parked", 26, ConsoleOutput); 

  
  /*wait for condition variable*/
  Signal(parkingLock,waitForCars);
  Wait(parkingLock,limoReadyToPark);
  Release(parkingLock);


}


void removingLimoPassengers(int number, char *name){

  int limoNum = number;

  /*atomic operation
   *get lock to deal with people in car
   */
  Acquire(limoLock[limoNum]);

  /*driver meets valet and tells visitors to exit.*/


  Write("Visitors from Limo ", 14, ConsoleOutput);
  PrintInt(limoNum);
  Write (" can now exit the Limo\n", 23, ConsoleOutput); 

  Broadcast(limoLock[limoNum],visitorLimoExit[limoNum]);
  Release(limoLock[limoNum]);

  /*code for exiting the car
   *enter the car monitor
   */  
  Acquire(limoLock[limoNum]);
  /*check if all passengers have exited the car*/
  if (limoPassengers[limoNum] > 0){
    /*this means passengers are still in the car
     *make driver wait for the condition variable
     */
    Write(name, 4, ConsoleOutput);
    PrintInt(limoNum);
    Write (" is waiting for passengers to exit\n", 35, ConsoleOutput); 

    Wait(limoLock[limoNum], limoWaitingCV[limoNum]);
    Write(name, 4, ConsoleOutput);
    Write(" ",1,ConsoleOutput);
    PrintInt(limoNum);
    Write (" is exiting the limo\n",21,ConsoleOutput);
  } else{
    /*all passengers have exited*/
    Write(name, 4, ConsoleOutput);
    Write(" ",1,ConsoleOutput);
    PrintInt(limoNum);
    Write (" is exiting the limo\n", 21, ConsoleOutput);    
  }
  
  /*exit the monitor*/
  Release(limoLock[limoNum]);
}


/* Removing passengers from the cars*/

void removingPassengers(int number, char *name){
  int carNum = number;

  /*atomic operation
   *get lock to deal with people in car
  */
  Acquire(carLock[carNum]);

  /*driver meets valet and tells visitors to exit.*/

  Write("Visitors from car ", 13, ConsoleOutput);
  PrintInt(carNum);
  Write (" can now exit the Car\n", 22, ConsoleOutput); 

  Broadcast(carLock[carNum],visitorExit[carNum]);
  Release(carLock[carNum]);

  /*code for exiting the car*/
  Acquire(carLock[carNum]);
  
  /*check if all passengers have exited the car*/
  if (passengers[carNum] > 0){
    /*this means passengers are still in the car
     *make driver wait for the condition variable
     */
    Write(name, 3, ConsoleOutput);
    PrintInt(carNum);
    Write (" is waiting for passengers to exit\n", 35, ConsoleOutput);
    Wait(carLock[carNum],driverWaitingCV[carNum]);
    
  } else{
    //all passengers have exited
    Write(name, 3, ConsoleOutput);
    PrintInt(carNum);
    Write (" is exiting the car\n", 20, ConsoleOutput); 
  }
  
  //exit the monitor
  Release(carLock[carNum]);
}



/*code for the getting the Parking Token*/
void gettingParkingToken(int number, char *name){
 
  int carNum = number;
 
  /*getting the lock to enter atomic operation*/
  Acquire(carLock[carNum]);
  Write("Driver ",7, ConsoleOutput);
  PrintInt(carNum);
  Write(" hands over the keys to the Valet\n",34,ConsoleOutput);

  Signal(carLock[carNum],hasKey[carNum]);

  //wait for a parking token from the valet
  Write("Driver ",7, ConsoleOutput);
  PrintInt(carNum);
  Write(" is waiting for the parking token\n",32,ConsoleOutput);
  Wait(carLock[carNum],hasToken[carNum]);

  //message saying they recieved the token
  Write("Driver ",7, ConsoleOutput);
  PrintInt(carNum);
  Write(" has received a parking token\n",30,ConsoleOutput);

  //release the lock
  Release(carLock[carNum]);
}

void gettingLimoParkingToken(int number, char *name){

  int carNum = number;
 
  /*getting the lock to enter atomic operation*/
  Acquire(limoLock[carNum]);
  Write("Limo Driver ",12, ConsoleOutput);
  PrintInt(carNum);
  Write(" hands over the keys to the Valet\n",34,ConsoleOutput);

  Signal(limoLock[carNum],limoHasKey[carNum]);

  //wait for a parking token from the valet
  Write("Limo Driver ",12, ConsoleOutput);
  PrintInt(carNum);
  Write(" is waiting for the parking token\n",32,ConsoleOutput);
  Wait(limoLock[carNum],limoHasToken[carNum]);

  //message saying they recieved the token
  Write("Limo Driver ",12, ConsoleOutput);
  PrintInt(carNum);
  Write(" has received a parking token\n",30,ConsoleOutput);

  //release the lock
  Release(limoLock[carNum]);
}


void gettingMuseumLine(int number, char *name){

  int carNum = number;
 
  Acquire(lineLock);
  /*if no one is in line wake up the ticket taker*/
  if (ticketLineCount == 0){
    Write("Waking up the Ticket Taker\n ",27,ConsoleOutput);
    Signal(lineLock,waitOnCustomers);
  }

  /*increment the in line count*/
  ticketLineCount ++;
  Write(name,7,ConsoleOutput);
  PrintInt(carNum);
  Write(" is getting in line for the Ticket Taker\n",38, ConsoleOutput);
  Wait(lineLock,ticketLine); 
  Release(lineLock);
}


/*************************
 *Driver Thread 
 */


void Driver(int number){

  char* name;
  name = "Driver";
  int carNum = number;


  //car arrive at the museum
  driveInMuseum(number,name);

  //removing people from the car
  removingPassengers(number,name);

  //getting parking token from the valet
  gettingParkingToken(number,name);

  /*getting Museum Line, interact with TicketTaker*/
  gettingMuseumLine();

  Write("Driver ",7,ConsoleOutput);
  PrintInt(carNum);
  Write(" is entering the museum\n",23,ConsoleOutput);
  
  inMuseum ++;
  goToMuseum();
  
  Write("Driver ",7,ConsoleOutput);
  PrintInt(carNum);
  Write(" is exiting the museum\n",22,ConsoleOutput);


  /*get the lock to wait for visitor to leave the museum
   *wait for everyone to exit the museum
   *  if driver is alone he will not get onto the leaving CV*/
  Acquire(carLock[carNum]);
  if (outOfCar[carNum] > 0){
    Write("Driver ",7, ConsoleOutput);
    PrintInt(carNum);
    Write(" is waiting for everyone to exit\n",33, ConsoleOutput);
    Wait(carLock[carNum],readyToLeave[carNum]);
  }
  Release(carLock[carNum]);


  /*tell the valet they want to leave
   *get in line to get a valet so the car can leave
   */  
  Acquire(parkingLock);
  driverWaiting ++;
  Write("Driver ",7, ConsoleOutput);
  PrintInt(carNum);
  Write(" calls the Valet\n",17, ConsoleOutput);
  Signal(parkingLock1,waitForCars);

  /*wait for the valet to come and help them*/
  Write("Driver ",7, ConsoleOutput);
  PrintInt(carNum);
  Write(" is waiting for a valet\n",24,ConsoleOutput);
  AddtoList(carNum,carnumbersLeave);
  Wait(parkingLock,leaving);
  Release(parkingLock);



  /*give parking token to the valet to get the car back*/
  carLock[carNum]->Acquire(carLock[carNum]);
  Write("Driver ",7,ConsoleOutput);
  PrintInt(carNum);
  Write(" gives his parking token to Valet\n",34,ConsoleOutput);
  Signal(carLock[carNum],leaveToken[carNum});
  /*wait for the valet to return with the car*/
  Write("Driver ",7,ConsoleOutput);
  PrintInt(carNum);
  Write(" is waiting for his car\n",24,ConsoleOutput);
  Wait(carLock[carNum],waitCarLeaving[carNum]);
  /*tip the valet*/
  Write("Driver ",7,ConsoleOutput);
  PrintInt(carNum);
  Write(" tips the Valet\n",17,ConsoleOutput);
  Signal(carLock[carNum],Tip[carNum]);
  /*wait for acknowledgement of tip from valet*/
  Wait(carLock[carNum],canLeave[carNum]);

  /*tell all visitors they can get in the car*/
  Write("Everyone from car ",17,ConsoleOutput);
  PrintInt(carNum);
  Write(" can get in the Car\n",19,ConsoleOutput);
  Broadcast(carLock[carNum],waitToLeave[carNum]);

  /*check if driver did not have any passengers*/
  if(passengers[carNum] > 0){
    /*if driver did have passengers wait for all of them
     *to get back in the car*/
    Write("Driver ",7,ConsoleOutput);
    PrintInt(carNum);
    Write(" is waiting for everyone to get in\n",31,ConsoleOutput);
    Wait(carLock[carNum],readyToLeave[carNum]);
  }    

  /*tell all visitors they are leaving the museum*/
  Write("Driver ",7, ConsoleOutput);
  PrintInt(carNum);
  Write(" gets into the Car and leaves Museum\n",35,ConsoleOutput);
  Broadcast(carLock[carNum],waitExit[carNum]);

  Release(carLock[carNum]);
}


void limoDriver(int number){

  char* name;
  name = "Limo Driver ";
  int carNum = number;


  limoDriveInMuseum(number,name);

  removingLimoPassengers(number,name);

  gettingLimoParkingToken(number,name);


  /*wait for everyone exit the museum*/
  Acquire(limoLock[carNum]);
  /*wait for everyone to exit the museum
   *if driver is alone he will not get onto the leaving CV*/
  if (limoOutOfCar[carNum] > 0){
    Write("Limo Driver ",12,ConsoleOutput);
    PrintInt(carNum);
    Write(" is waiting for everyone to exit\n",30,ConsoleOutput);
    Wait(limoLock[carNum],limoReadyToLeave[carNum]);
  }
  Release(limoLock[carNum]);



  /*Everybody back to the limo tell the valet they want to leave*/
  Acquire(parkingLock);
  limoWaiting ++;
  Write("Limo Driver ",12,ConsoleOutput);
  PrintOut(carNum);
  Write(" calls the Valet\n",16,ConsoleOutput);
  Signal(parkingLock,waitForCars);
  /*wait for the valet to come and help them*/
  Write("Limo Driver ",12,ConsoleOutput);
  PrintInt(carNum);
  Write(" is waiting for a Valet\n",21,ConsoleOutput);
  AddtoList(carNum,limoListToLeave);
  Wait(parkingLock,limoLeaving);
  Release(parkingLock);




  /*give the valet the token in order to get the limo back*/
  Acquire(limoLock[carNum]);
  /*give the parking token to the valet*/
  Write("Limo Driver ",12,ConsoleOutput);
  PrintInt(carNum);
  Write(" gives his parking token to Valet\n",21,ConsoleOutput);
  Signal(limoLock[carNum],limoLeaveToken[carNum]);
  /*wait for the valet to return with the car*/
  Write("Limo Driver ",12,ConsoleOutput);
  PrintInt(carNum);
  Write(" is waiting for his Limo\n",20,ConsoleOutput);
  Wait(limoLock[carNum],waitLimoLeaving[carNum]);
  Release(limoLock[carNum]);


 
  /*tip the valet to get the limo back*/
  Acquire(limoLock[carNum]);
  Write("Limo Driver ",12,ConsoleOutput);
  PrintInt(carNum);
  Write(" tips the Valet\n",14,ConsoleOutput);
  Signal(limoLock[carNum],limoTip[carNum]);
  /*wait for acknowledgement of tip from valet*/
  Wait(limoLock[carNum],limoCanLeave[carNum]);

  /*tell all visitors they can get in the car*/
  Write("Everyone from Limo ",17,ConsoleOutput);
  PrintInt(carNum);
  Write(" can get in the Limo\n",18,ConsoleOutput);
  Broadcast(limoLock[carNum],limoWaitToLeave[carNum]);

  /*check if driver did not have any passengers*/
  if(limoPassengers[carNum] > 0){
    /*if driver did have passengers wait for all of them
     *to get back in the car*/
    Write("Limo Driver ",12,ConsoleOutput);
    PrintInt(carNum);
    Write(" is waiting for everyone to get in\n",31,ConsoleOutput);
    Wait(limoLock[carNum],limoReadyToLeave[carNum]);
  }    

  /*tell all visitors they are leaving the museum*/
  
  Write("Limo Driver ",12,ConsoleOutput);
  PrintInt(carNum);
  Write(" gets into the Limo and leaves Museum\n",32,ConsoleOutput);
  Broadcast(limoLock[carNum],limoWaitExit[carNum]);
  Release(limoLock[carNum]);

}


/*
 *visitor code       
 */
void Visitor(int data){
  
  visInfo* info = (visInfo*) data;

  char* name = info->name;
  int num = info->visNum;
  
  if (info->limo){  

    int carNum = info->limoNum;
    
    //code to check for exit
    limoLock[carNum]->Acquire();
    
    //make visitor wait to exit the car
    cout<<"Visitor "<<num<<" is waiting to exit Limo "<<carNum<<endl;
    visitorLimoExit[carNum]->Wait(limoLock[carNum]);
    
    //release the lock
    limoLock[carNum]->Release();
    
    //code to exit a car
    limoLock[carNum]->Acquire();
    
    //actually exit the car
    if(limoLock[carNum]->isHeldByCurrentThread()){
      //print message so you know its happening
      cout<<"Visitor "<<num<<" is exiting Limo "<<carNum<<endl;
      //decrement the passengers in the car
      limoPassengers[carNum] --;
      //increment passengers out of the car
      limoOutOfCar[carNum] ++;
    }else{
      //print error message if thread does not have the lock
      cout<<"Current thread does not hold the lock"<<endl;
    }
    
    if(limoPassengers[carNum] == 0){
      //this means car is empty
      //signal the driver to tell them car is empty
      cout<<"All passengers have exited Limo "<<carNum<<endl;
      limoWaitingCV[carNum]->Signal(limoLock[carNum]);
    }
    
    //exit the monitor
    limoLock[carNum]->Release();
    
    //get the lock to get in line
    lineLock->Acquire();
    
    //check to see if anyone is in line to get their ticket taken
    if (ticketLineCount == 0){
      //if no one is in line wake up the ticket taker
      cout<<"Visitor "<<num<<" is waking up the Ticket Taker"<<endl;
      waitOnCustomers->Signal(lineLock);
      //increment the number of people in line
      ticketLineCount ++;
      //get in line
      cout<<"Visitor "<<num<<" is getting in line for the Ticket Taker"<<endl;
      ticketLine->Wait(lineLock);
    }else{
      //if there are people in line increment the count and get in line
      ticketLineCount ++;
      cout<<"Visitor "<<num<<" is getting in line for the Ticket Taker"<<endl;
      ticketLine->Wait(lineLock);
    }
    
    //release the lock
    lineLock->Release();
    
    //go to the museum
    cout<<"Visitor "<<num<<" is entering the museum"<<endl;
    goToMuseum();
    cout<<"Visitor "<<num<<" is exiting the museum"<<endl;
    
    //acquire the car lock
    limoLock[carNum]->Acquire();
    
    //decrement here so the last will know they are the last
    limoOutOfCar[carNum] --;
    limoPassengers[carNum] ++;
    
    //checking to see how many people are waiting for a car
    if (limoOutOfCar[carNum] > 0){
      cout<<"Visitor "<<num<<" is waiting for everyone to leave the Museum"<<endl;
      limoWaitToLeave[carNum]->Wait(limoLock[carNum]);
    }else{
      //if everyone is out of the museum tell the driver
      cout<<"All Visitors from Limo "<<carNum<<" are back"<<endl;
      limoReadyToLeave[carNum]->Signal(limoLock[carNum]);
      limoWaitToLeave[carNum]->Wait(limoLock[carNum]);
    }
    
    //cout<<passengers[carNum]<<endl;
    //decrement ahead so that the last passenger will know they are the last
    limoPassengers[carNum] --;
    
    //check if all the passengers are in the car
    if(limoPassengers[carNum] > 0){
      cout<<"Visitor "<<num<<" is getting in Limo "<<carNum<<endl;
    }else{
      //if all passengers are in the car print message and tell driver
      cout<<"Visitor "<<num<<" is getting in Limo "<<carNum<<endl;
      cout<<"All Visitors are in Limo "<<carNum<<endl;
      limoReadyToLeave[carNum]->Signal(limoLock[carNum]);
    }
    
    //wait for driver to drive off
    cout<<"Visitor "<<num<<" is waiting for Limo "<<carNum<<" to drive off"<<endl;
    limoWaitExit[carNum]->Wait(limoLock[carNum]);
    
    //release the lock
    limoLock[carNum]->Release();
  } else {
    
    
    ////////////////////////////////car code///////////////////////////
    
    int carNum = info->carNum;
    
    //code to check for exit
    carLock[carNum]->Acquire();
    
    //make visitor wait to exit the car
    cout<<"Visitor "<<num<<" is waiting to exit Car "<<carNum<<endl;
    visitorExit[carNum]->Wait(carLock[carNum]);
    
    //release the lock
    carLock[carNum]->Release();
    
    //code to exit a car
    carLock[carNum]->Acquire();
    
    //actually exit the car
    if(carLock[carNum]->isHeldByCurrentThread()){
      //print message so you know its happening
      cout<<"Visitor "<<num<<" is exiting the car"<<endl;
      //decrement the passengers in the car
      passengers[carNum] --;
      //increment passengers out of the car
      outOfCar[carNum] ++;
    }else{
      //print error message if thread does not have the lock
      cout<<"Current thread does not hold the lock"<<endl;
    }
    
    if(passengers[carNum] == 0){
      //this means car is empty
      //signal the driver to tell them car is empty
      cout<<"All passengers have exited Car "<<carNum<<endl;
      driverWaitingCV[carNum]->Signal(carLock[carNum]);
    }
    
    //exit the monitor
    carLock[carNum]->Release();
    
    //get the lock to get in line
    lineLock->Acquire();
    
    //check to see if anyone is in line to get their ticket taken
    if (ticketLineCount == 0){
      //if no one is in line wake up the ticket taker
      cout<<"Visitor "<<num<<" is waking up the Ticket Taker"<<endl;
      waitOnCustomers->Signal(lineLock);
      //increment the number of people in line
      ticketLineCount ++;
      //get in line
      cout<<"Visitor "<<num<<" is getting in line for the Ticket Taker"<<endl;
      ticketLine->Wait(lineLock);
    }else{
      //if there are people in line increment the count and get in line
      ticketLineCount ++;
      cout<<"Visitor "<<num<<" is getting in line for the Ticket Taker"<<endl;
      ticketLine->Wait(lineLock);
    }
    
    //release the lock
    lineLock->Release();
    
    //go to the museum
    cout<<"Visitor "<<num<<" is entering the museum"<<endl;
    goToMuseum();
    cout<<"Visitor "<<num<<" is exiting the museum"<<endl;
    
    //acquire the car lock
    carLock[carNum]->Acquire();
    
    //decrement here so the last will know they are the last
    outOfCar[carNum] --;
    passengers[carNum] ++;
    
    //checking to see how many people are waiting for a car
    if (outOfCar[carNum] > 0){
      cout<<"Visitor "<<num<<" is waiting for everyone to leave the Museum"<<endl;
      waitToLeave[carNum]->Wait(carLock[carNum]);
    }else{
      //if everyone is out of the museum tell the driver
      cout<<"All Visitors from car "<<carNum<<" are back"<<endl;
      readyToLeave[carNum]->Signal(carLock[carNum]);
      waitToLeave[carNum]->Wait(carLock[carNum]);
    }
    
    //cout<<passengers[carNum]<<endl;
    //decrement ahead so that the last passenger will know they are the last
    passengers[carNum] --;
    
    //check if all the passengers are in the car
    if(passengers[carNum] > 0){
      cout<<"Visitor "<<num<<" is getting in Car "<<carNum<<endl;
    }else{
      //if all passengers are in the car print message and tell driver
      cout<<"Visitor "<<num<<" is getting in Car "<<carNum<<endl;
      cout<<"All Visitors are in Car "<<carNum<<endl;
      readyToLeave[carNum]->Signal(carLock[carNum]);
    }
    
    //wait for driver to drive off
    cout<<"Visitor "<<num<<" is waiting for Car "<<carNum<<" to drive off"<<endl;
    waitExit[carNum]->Wait(carLock[carNum]);
    
    //release the lock
    carLock[carNum]->Release();
  }
  
}  

/*
 *Ticket Taker       //
 */
void TicketTaker(){
  while (true){
    Acquire(lineLock);
    /*check the count to see if people are in line*/
    if (ticketLineCount > 0){
      /*accept the ticket from the first person in line*/
      Write("Ticket accepted***\n",17,ConsoleOutput);
      Signal(lineLock,ticketLine);
      /*decrement the count of people in line*/
      ticketLineCount --;
    }else{
      /*if no one is in line go to sleep*/
      Write("Ticket Taker is waiting for customers\n",28,ConsoleOutput);
      Wait(lineLock,waitOnCustomers);

    }
    Release(lineLock);
  }
}


/******************************
 *Valet              
 ******************************/

/*function for valet to park a car*/
void parkCar(int currentcar, int myNum){

  /*atomic operation to approach the car*/
  Acquire(parkingLock);
  /*set the car you are working with*/
  currentcar =(int)RemovefromList(carnumbersArrive);
  /*Tell the driver they are there to help them*/
  Write("Valet ",6,ConsoleOuput);
  PrintInt(myNum);
  Write(" has approached Car ",17,ConsoleOuput);
  PrintInt(currentcar);
  Write("\n",1,,ConsoleOuput);

  Signal(parkingLock,readyToPark);
  /*decrement the number of cars in line to be parked*/
  inLine --;
  //release the lock
  Release(parkingLock);



  /*get the current car's lock and exchange parking token*/
  Acquire(carLock[currentcar]);
  /*wait for the keys from the driver*/
  Write("Valet ",6, ConsoleOutput);
  PrintInt(myNum);
  Write(" is waiting for Driver's Keys\n",27, ConsoleOutput);
  Wait(carLock[currentcar],hasKeys[currentcar]);
  /*message saying they recieved the keys*/
  Write("Valet ",6, ConsoleOutput);
  PrintInt(myNum);
  Write(" has received the keys and hands over a parking token\n",51, ConsoleOutput);
  Signal(carLock[currentcar],hasToken[currentcar]);
  /*go and park the car*/
  Write("Valet ",6, ConsoleOutput);
  PrintInt(myNum);
  Write(" is parking the car\n",17, ConsoleOutput);
  /*release the lock*/
  Release(carLock[currentcar]);



  /*get a random number between 5 and 20 to park the car*/
  int randomNum = rand()%21 + 5;
  for(int i = randomNum; i>0; i--){
    currentThread->Yield();
  }
  Write("Car ",4, ConsoleOutput);
  PrintInt(currentcar);
  Write(" has been parked\n",17, ConsoleOutput);

  /*reset current car so it doesnt mess up other cars*/
  currentcar = -1;
}

/*code for parking the limo*/
void parkLimo(int currentcar, int myNum){
  /*atomic operation*/
  Acquire(parkingLock);
  /*set the car you are working with*/
  currentcar = (int)RemovefromList(limoListToPark);
  /*Tell the driver they are there to help them*/
  Write("Valet ",6,ConsoleOuput);
  PrintInt(myNum);
  Write(" has approached Limo ",18,ConsoleOuput);
  PrintInt(currentcar);
  Write("\n",1,,ConsoleOuput);
  Signal(parkingLock,limoReadyToPark);
  /*decrement the number of cars in line to be parked*/
  limoLine --;
  /*release the lock*/
  Release(parkingLock);


  /*get the current car's lock to exchange the token*/
  Acquire(limoLock[currentcar]);
  /*wait for the keys from the driver*/
  Write("Valet ",6, ConsoleOutput);
  PrintInt(myNum);
  Write(" is waiting for Limo Driver's Keys\n",32, ConsoleOutput);
  Wait(limoLock[currentcar],limoHasKeys[currentcar]);
  /*message saying they recieved the keys*/
  Write("Valet ",6, ConsoleOutput);
  PrintInt(myNum);
  Write(" has received the keys and hands over a parking token for Limo Driver\n",67, ConsoleOutput);
  Signal(limoLock[currentcar],limoHasToken[currentcar]);
  /*go and park the car*/
  Write("Valet ",6, ConsoleOutput);
  PrintInt(myNum);
  Write(" is parking the Limo\n",18, ConsoleOutput);
  Release(limoLock[currentcar]);

  /*get a random number between 5 and 20 to generate the time to park limo*/
  int randomNum = rand()%21 + 5;
  for(int i = randomNum; i>0; i--){
    currentThread->Yield();
  }
  Write("Limo ",5, ConsoleOutput);
  PrintInt(currentcar);
  Write(" has been parked\n",17, ConsoleOutput);

  /*reset current car so it doesnt mess up other cars*/
  currentcar = -1;
}



/*function for a valet to retrieve a car*/
void retrieveCar(int currentcar, int myNum){
  /*atomic operation to identify the car*/
  Acquire(parkingLock);
  /*set the car the valet is working with*/
  currentcar = (int)RemovefromList(carnumbersLeave);
  /*decrement the driver waiting to leave coutnt*/
  driverWaiting --;
  /*tells the driver they are there to help them*/
  Write("Valet ",6,ConsoleOuput);
  PrintInt(myNum);
  Write(" has approached Car ",20,ConsoleOutput);
  Print(currentcar);
  Write(" and gets his Token\n",21,ConsoleOutput);
  Signal(parkingLock,leaving);
  Release(parkingLock);


  /*get the current car's lock*/
  Acquire(carLock[currentcar]);
  /*get the car from the parking lot*/
  Write("Valet ",6,ConsoleOuput);
  PrintInt(myNum);
  Write(" is getting Car ",14,ConsoleOuput);
  PrintInt(currentcar);
  Write("\n",1,,ConsoleOuput);  
  Release(carLock[currentcar]);


  /*get a random number between 5 and 20 to get the car*/
  int randomNum = rand()%21 + 5;
  for(int i = randomNum; i>0; i--){
    currentThread->Yield();
  }


  Acquire(carLock[currentcar]);
  /*tell the driver they have returned with the car*/
  Write("Valet ",6, ConsoleOutput);
  PrintInt(mynum);
  Write(" has returned with Car\n",20, ConsoleOutput);
  Signal(carLock[currentcar],waitCarLeaving[currentcar]);

  /*wait for a tip from the driver*/
  Write("Valet ",6, ConsoleOutput);
  PrintInt(mynum);
  Write("is waiting for his tip\n",20, ConsoleOutput);
  Wait(carLock[currentcar],Tip[currentcar]);
  /*message that they recieved the tip*/
  Write("Valet ",6, ConsoleOutput);
  PrintInt(mynum);
  Write(" has received for his tip\n",20, ConsoleOutput);
 
  /*tell the driver that they can get in the car and leave*/
  Write("Car ",4, ConsoleOutput);
  PrintInt(currentcar);
  Write(" can get ready to leave\n",20, ConsoleOutput);
  Signal(carLock[currentcar],canLeave[currentcar]);
  Release(carLock[currentcar]);

  /*reset current car so it doesnt mess up other cars*/
  currentcar = -1;

}

/***************************
 *Done up to here***********
 **************************/

void retrieveLimo(int currentcar, int myNum){
  int randomNum = 20;
  int i;

  /*enter atomic operation to retrieve the limo*/
  Acquire(parkingLock);
  /*set the car the valet is working with*/
  currentcar = (int)RemovefromList(limoListToLeave);
  /*decrement the driver waiting to leave coutnt*/
  limoWaiting --;
  /*tells the driver they are there to help them*/
  Write("Valet ",6,ConsoleOuput);
  PrintInt(myNum);
  Write(" has approached Limo ",21,ConsoleOutput);
  Print(currentcar);
  Write(" and gets his Token\n",21,ConsoleOutput);
  Signal(parkingLock,limoLeaving);
  Release(parkingLock);

  /*get the current car's lock*/
  Acquire(limoLock[currentcar]);

  /*wait for a parking token from the driver
   *cout<<"Valet "<<myNum<<" is waiting for a parking token"<<endl;
   *limoLeaveToken[currentcar]->Wait(limoLock[currentcar]); 

   *message saying they got the token
   *cout<<"Valet "<<myNum<<" has recieved a parking token"<<endl;*/
  
  /*get the car from the parking lot*/
  Write("Valet ",6,ConsoleOuput);
  PrintInt(myNum);
  Write(" is getting Car ",14,ConsoleOuput);
  PrintInt(currentcar);
  Write("\n",1,,ConsoleOuput);  
  Release(limoLock[currentcar]);
  
  
  /*simulate time to get the car*/
  for(i = randomNum; i>0; i--){
    currentThread->Yield();
  }

  /*drive back the car to get the tips*/
  Acquire(limoLock[currentcar]);
  /*tell the driver they have returned with the car*/
  Write("Valet ",6, ConsoleOutput);
  PrintInt(mynum);
  Write(" has returned with Limo\n",21, ConsoleOutput);
  Signal(limoLock[currentcar],waitLimoLeaving[currentcar]);

  /*wait for a tip from the driver*/
  Write("Valet ",6, ConsoleOutput);
  PrintInt(mynum);
  Write("is waiting for his tip\n",20, ConsoleOutput);
  Wait(limoLock[currentcar],limoTip[currentcar]);

  /*message that they recieved the tip*/
  Write("Valet ",6, ConsoleOutput);
  PrintInt(mynum);
  Write(" has received for his tip\n",20, ConsoleOutput);

  /*tell the driver that they can get in the car and leave*/
  Write("Limo ",5, ConsoleOutput);
  PrintInt(currentcar);
  Write(" can get ready to leave\n",20, ConsoleOutput);
  Signal(limoLock[currentcar],limoCanLeave[currentcar]);
  Release(limoLock[currentcar]);

  /*reset current car so it doesnt mess up other cars*/
  currentcar = -1;
}


bool correctTest = false;
int numInBack = 0;

void Valet(int valetNum){

  int currentcar = -1;
  int myNum = valetNum;
  
  while(true){
    /*Order of priority: park limos, retrieve limos, retrieve cars, park cars*/
    if (limoLine>0){
      parkLimo(currentcar, myNum);
    }else if (limoWaiting != 0){
      retrieveLimo(currentcar, myNum);
    }else if(driverWaiting != 0){
      retrieveCar(currentcar, myNum);
    }else if (inLine != 0){
      parkCar(currentcar, myNum);
    } 
    
    /*if another valet is already asleep get ready to go to back room*/
    if (onBench >= 1 && correctTest){
      Acquire(breakLock);
      /*increment the on bench value*/
      onBench ++;
      /*signal the manager that you need to go on break*/
      Signal(breakLock,managerWaiting);
      Write("Valet ",6,ConsoleOutput);
      PrintInt(myNum);
      Write(" is sleeping on the bench!!\n",26,ConsoleOutput);
      /*wait to be sent on break*/
      Wait(breakLock,waitForBreak);
      onBench --;
      numInBack ++;
      Write("Manager sends Valet ",19,ConsoleOuput);
      PrintInt(myNum);
      Write(" to the back room\n",18,ConsoleOutput);
      /*go on break*/
      Wait(breakLock,backRoom);
      /*sent back to work*/
      Write("Manager sends Valet ",19);
      PrintInt(myNum);
      Write(" back to work\n",15,ConsoleOutput);
      numInBack --;
      Release(breakLock);
    }

    /*update sum value*/
    sum = limoWaiting + limoLine + inLine + driverWaiting;
    
    Acquire(parkingLock);
    /*if there are no cars go to sleep*/
    if (inLine == 0 && driverWaiting == 0 && limoLine == 0 && limoWaiting == 0){
      onBench++;
      Write("Valet ",6,ConsoleOutput);
      PrintInt(myNum);
      Write(" is sleeping on the bench!!\n",26,ConsoleOutput); 
      Wait(parkingLock,waitForCars);
      onBench--;
    }
    Release(parkingLock);
  }
}


/*Valet Manager send Valet on Break*/
void sendOnBreak(){
  /*signal the valet to go on break*/
  waitForBreak->Signal(breakLock);      
}

/*Valet Manager signal the valet to go back to work*/
void goBackToWork(){
  backRoom->Signal(breakLock);
}


/*Valet Manager code*/
void valetManager(){
  while (true){
    /*The valet manager own the breakLock*/
    Acquire(breakLock);
    /*update the sum value to the newest amount*/
    sum = limoWaiting + limoLine + inLine + driverWaiting;
    if(onBench >= 1){/*if more than one valet is on the bench send one on break*/
      sendOnBreak();
    }
    if (sum >= 4){/*if more than 4 cars are waiting to be handled send a valet back out*/
      goBackToWork();
    }
    Release(breakLock);
  }
}


//global variables used to start each test
int numberOfCars;
int numberLimo;
int numTT;
int numValet;
int numVis;
bool manager = false;


void test1(){
  //initialize threads for the test
  Thread *driver;
  driver = new Thread("driver");

  passengers[0] = 2;

  Thread *valet;
  valet = new Thread("valet");

  Thread *tickettaker;
  tickettaker = new Thread("ticket taker");

  Thread** visitors;
  visitors = new Thread* [numVis];

  for (int i = 0; i <numVis; i ++){
    visitors[i] = new Thread("Visitor");
  }
  
  visInfo** data;
  data = new visInfo* [numVis];

  for (int i = 0; i <numVis; i ++){
    data[i] = new visInfo;
  }
  
  //fork the threads
  driver->Fork((VoidFunctionPtr)Driver,0);
  valet->Fork((VoidFunctionPtr)Valet,0);
  tickettaker->Fork((VoidFunctionPtr)TicketTaker,0);
  
  for (int i = 0; i <numVis; i ++){
    data[i]->name = "Visitor";
    data[i]->carNum = 0;
    data[i]->limoNum = -1;
    data[i]->limo = false;
    data[i]->visNum = i;
    visitors[i]->Fork((VoidFunctionPtr)Visitor,(int)data[i]);
  }

}
  
void test2(){
  Thread *driver;
  driver = new Thread("driver");

  Thread *valet0;
  valet0 = new Thread("valet");

  Thread *valet1;
  valet1 = new Thread("valet");

  Thread *limo0;
  limo0 = new Thread("limo");

  Thread *limo1;
  limo1 = new Thread("limo");

  Thread *limo2;
  limo2 = new Thread("limo");

  Thread *limo3;
  limo3 = new Thread("limo");

  Thread *limo4;
  limo4 = new Thread("limo");

  valet0->Fork((VoidFunctionPtr)Valet,0);
  valet1->Fork((VoidFunctionPtr)Valet,1);
  limo0->Fork((VoidFunctionPtr)limoDriver,0);
  limo1->Fork((VoidFunctionPtr)limoDriver,1);
  driver->Fork((VoidFunctionPtr)Driver,0);
  limo2->Fork((VoidFunctionPtr)limoDriver,2);
  limo3->Fork((VoidFunctionPtr)limoDriver,3);
  limo4->Fork((VoidFunctionPtr)limoDriver,4);
}

void test3(){
  Thread *driver0;
  driver0 = new Thread("driver");

  Thread *driver1;
  driver1 = new Thread("driver");

  Thread *driver2;
  driver2 = new Thread("driver");

  Thread *driver3;
  driver3 = new Thread("driver");

  Thread *driver4;
  driver4 = new Thread("driver");

  Thread *driver5;
  driver5 = new Thread("driver");

  Thread *driver6;
  driver6 = new Thread("driver");

  Thread *driver7;
  driver7 = new Thread("driver");

  Thread *driver8;
  driver8 = new Thread("driver");

  Thread *driver9;
  driver9 = new Thread("driver");

  Thread *valet0;
  valet0 = new Thread("valet");

  Thread *valet1;
  valet1 = new Thread("valet");

  Thread *valet2;
  valet2 = new Thread("valet");

  valet0->Fork((VoidFunctionPtr)Valet,0);
  valet1->Fork((VoidFunctionPtr)Valet,1);
  valet2->Fork((VoidFunctionPtr)Valet,2);
  driver0->Fork((VoidFunctionPtr)Driver,0);
  driver1->Fork((VoidFunctionPtr)Driver,1);
  driver2->Fork((VoidFunctionPtr)Driver,2);
  driver3->Fork((VoidFunctionPtr)Driver,3);
  driver4->Fork((VoidFunctionPtr)Driver,4);
  driver5->Fork((VoidFunctionPtr)Driver,5);
  driver6->Fork((VoidFunctionPtr)Driver,6);
  driver7->Fork((VoidFunctionPtr)Driver,7);
  driver8->Fork((VoidFunctionPtr)Driver,8);
  driver9->Fork((VoidFunctionPtr)Driver,9);

}
void test4(){
  Thread *valet0;
  valet0 = new Thread("valet");

  Thread *valet1;
  valet1 = new Thread("valet");

  Thread *valet2;
  valet2 = new Thread("valet");

  Thread *valet3;
  valet3 = new Thread("valet");

  Thread *valet4;
  valet4 = new Thread("valet");

  Thread *limo0;
  limo0 = new Thread("limo");

  Thread *limo1;
  limo1 = new Thread("limo");

  Thread *limo2;
  limo2 = new Thread("limo");

  Thread *limo3;
  limo3 = new Thread("limo");

  Thread *limo4;
  limo4 = new Thread("limo");

  Thread *limo5;
  limo5 = new Thread("limo");

  Thread *limo6;
  limo6 = new Thread("limo");

  Thread *limo7;
  limo7 = new Thread("limo");

  Thread *limo8;
  limo8 = new Thread("limo");

  Thread *limo9;
  limo9 = new Thread("limo");

  valet0->Fork((VoidFunctionPtr)Valet,0);
  valet1->Fork((VoidFunctionPtr)Valet,1);
  valet2->Fork((VoidFunctionPtr)Valet,2);
  valet3->Fork((VoidFunctionPtr)Valet,3);
  valet4->Fork((VoidFunctionPtr)Valet,4);
  limo0->Fork((VoidFunctionPtr)limoDriver,0);
  limo1->Fork((VoidFunctionPtr)limoDriver,1);
  limo2->Fork((VoidFunctionPtr)limoDriver,2);
  limo3->Fork((VoidFunctionPtr)limoDriver,3);
  limo4->Fork((VoidFunctionPtr)limoDriver,4);
  limo5->Fork((VoidFunctionPtr)limoDriver,5);
  limo6->Fork((VoidFunctionPtr)limoDriver,6);
  limo7->Fork((VoidFunctionPtr)limoDriver,7);
  limo8->Fork((VoidFunctionPtr)limoDriver,8);
  limo9->Fork((VoidFunctionPtr)limoDriver,9);
}

void test5(){
  Thread *driver0;
  driver0 = new Thread("driver");

  Thread *driver1;
  driver1 = new Thread("driver");

  Thread *driver2;
  driver2 = new Thread("driver");

  Thread *limo0;
  limo0 = new Thread("limo");

  Thread *limo1;
  limo1 = new Thread("limo");

  driver0->Fork((VoidFunctionPtr)Driver,0);
  driver1->Fork((VoidFunctionPtr)Driver,1);
  driver2->Fork((VoidFunctionPtr)Driver,2);
  limo0->Fork((VoidFunctionPtr)limoDriver,0);
  limo1->Fork((VoidFunctionPtr)limoDriver,1);

}

void test6(){
  correctTest = true;

  Thread *valet0;
  valet0 = new Thread("valet");

  Thread *valet1;
  valet1 = new Thread("valet");

  Thread *valet2;
  valet2 = new Thread("valet");

  Thread *driver0;
  driver0 = new Thread("driver");

  Thread *limo0;
  limo0 = new Thread("limo");

  Thread *limo1;
  limo1 = new Thread("limo");

  Thread *limo2;
  limo2 = new Thread("limo");

  Thread *limo3;
  limo3 = new Thread("limo");

  Thread *limo4;
  limo4 = new Thread("limo");

  Thread *vmanager;
  vmanager = new Thread("valet manager");

  valet0->Fork((VoidFunctionPtr)Valet,0);
  valet1->Fork((VoidFunctionPtr)Valet,1);
  valet2->Fork((VoidFunctionPtr)Valet,2);
  driver0->Fork((VoidFunctionPtr)Driver,0);
  limo0->Fork((VoidFunctionPtr)limoDriver,0);
  limo1->Fork((VoidFunctionPtr)limoDriver,1);
  limo2->Fork((VoidFunctionPtr)limoDriver,2);
  limo3->Fork((VoidFunctionPtr)limoDriver,3);
  limo4->Fork((VoidFunctionPtr)limoDriver,4);
  vmanager->Fork((VoidFunctionPtr)valetManager,0);

}

void test7(){
  Thread *driver0;
  driver0 = new Thread("driver");

  Thread *limo0;
  limo0 = new Thread("limo");

  Thread *limo1;
  limo1 = new Thread("limo");

  Thread *valet0;
  valet0 = new Thread("valet");

  Thread *valet1;
  valet1 = new Thread("valet");

  Thread** visitors;
  visitors = new Thread* [numVis];

  for (int i = 0; i <numVis; i ++){
    visitors[i] = new Thread("Visitor");
  }
  
  visInfo** data;
  data = new visInfo* [numVis];

  for (int i = 0; i <numVis; i ++){
    data[i] = new visInfo;
  }

  passengers[0] = 4;
  limoPassengers[0] = 2;
  limoPassengers[1] = 2;

  valet0->Fork((VoidFunctionPtr)Valet,0);
  valet1->Fork((VoidFunctionPtr)Valet,1);
  driver0->Fork((VoidFunctionPtr)Driver,0);
  limo0->Fork((VoidFunctionPtr)limoDriver,0);
  limo1->Fork((VoidFunctionPtr)limoDriver,1);

  for (int i = 0; i <4; i ++){
    data[i]->name = "Visitor";
    data[i]->carNum = 0;
    data[i]->limoNum = -1;
    data[i]->limo = false;
    data[i]->visNum = i;
    visitors[i]->Fork((VoidFunctionPtr)Visitor,(int)data[i]);
  }
  for (int i = 4; i <6; i ++){
    data[i]->name = "Visitor";
    data[i]->carNum = -1;
    data[i]->limoNum = 0;
    data[i]->limo = true;
    data[i]->visNum = i;
    visitors[i]->Fork((VoidFunctionPtr)Visitor,(int)data[i]);
  }
  for (int i = 6; i <8; i ++){
    data[i]->name = "Visitor";
    data[i]->carNum = -1;
    data[i]->limoNum = 1;
    data[i]->limo = true;
    data[i]->visNum = i;
    visitors[i]->Fork((VoidFunctionPtr)Visitor,(int)data[i]);
  }

}
void test8(){
  Thread *driver0;
  driver0 = new Thread("driver");

  Thread *limo0;
  limo0 = new Thread("limo");

  Thread *limo1;
  limo1 = new Thread("limo");

  Thread *valet0;
  valet0 = new Thread("valet");

  Thread *valet1;
  valet1 = new Thread("valet");

  Thread *tickettaker;
  tickettaker = new Thread("ticket taker");

  Thread** visitors;
  visitors = new Thread* [numVis];

  for (int i = 0; i <numVis; i ++){
    visitors[i] = new Thread("Visitor");
  }
  
  visInfo** data;
  data = new visInfo* [numVis];

  for (int i = 0; i <numVis; i ++){
    data[i] = new visInfo;
  }

  passengers[0] = 4;
  limoPassengers[0] = 2;
  limoPassengers[1] = 2;

  valet0->Fork((VoidFunctionPtr)Valet,0);
  valet1->Fork((VoidFunctionPtr)Valet,1);
  tickettaker->Fork((VoidFunctionPtr)TicketTaker,0);
  driver0->Fork((VoidFunctionPtr)Driver,0);
  limo0->Fork((VoidFunctionPtr)limoDriver,0);
  limo1->Fork((VoidFunctionPtr)limoDriver,1);

  for (int i = 0; i <4; i ++){
    data[i]->name = "Visitor";
    data[i]->carNum = 0;
    data[i]->limoNum = -1;
    data[i]->limo = false;
    data[i]->visNum = i;
    visitors[i]->Fork((VoidFunctionPtr)Visitor,(int)data[i]);
  }
  for (int i = 4; i <6; i ++){
    data[i]->name = "Visitor";
    data[i]->carNum = -1;
    data[i]->limoNum = 0;
    data[i]->limo = true;
    data[i]->visNum = i;
    visitors[i]->Fork((VoidFunctionPtr)Visitor,(int)data[i]);
  }
  for (int i = 6; i <8; i ++){
    data[i]->name = "Visitor";
    data[i]->carNum = -1;
    data[i]->limoNum = 1;
    data[i]->limo = true;
    data[i]->visNum = i;
    visitors[i]->Fork((VoidFunctionPtr)Visitor,(int)data[i]);
  }


}
void test9(){
  Thread *driver0;
  driver0 = new Thread("driver");

  Thread *limo0;
  limo0 = new Thread("limo");

  Thread *valet0;
  valet0 = new Thread("valet");

  Thread *valet1;
  valet1 = new Thread("valet");

  Thread *tickettaker;
  tickettaker = new Thread("ticket taker");

  Thread *visitor0;
  visitor0 = new Thread("vis0");

  limoPassengers[0] = 1;

  visInfo *data0 = new visInfo();

  valet0->Fork((VoidFunctionPtr)Valet,0);
  valet1->Fork((VoidFunctionPtr)Valet,1);
  tickettaker->Fork((VoidFunctionPtr)TicketTaker,0);
  driver0->Fork((VoidFunctionPtr)Driver,0);
  limo0->Fork((VoidFunctionPtr)limoDriver,0);

  data0->name = "Visitor";
  data0->carNum = -1;
  data0->limoNum = 0;
  data0->limo = true;
  data0->visNum = 0;
  visitor0->Fork((VoidFunctionPtr)Visitor,(int)data0);


}

void test10(){
  Thread *driver0;
  driver0 = new Thread("driver");

  Thread *limo0;
  limo0 = new Thread("limo");

  Thread *valet0;
  valet0 = new Thread("valet");

  Thread *valet1;
  valet1 = new Thread("valet");

  Thread *tickettaker;
  tickettaker = new Thread("ticket taker");

  Thread** visitors;
  visitors = new Thread* [numVis];

  for (int i = 0; i <numVis; i ++){
    visitors[i] = new Thread("Visitor");
  }
  
  visInfo** data;
  data = new visInfo* [numVis];

  for (int i = 0; i <numVis; i ++){
    data[i] = new visInfo;
  }

  passengers[0] = 2;
  limoPassengers[0] = 2;

  valet0->Fork((VoidFunctionPtr)Valet,0);
  valet1->Fork((VoidFunctionPtr)Valet,1);
  tickettaker->Fork((VoidFunctionPtr)TicketTaker,0);
  driver0->Fork((VoidFunctionPtr)Driver,0);
  limo0->Fork((VoidFunctionPtr)limoDriver,0);

  for (int i = 0; i <2; i ++){
    data[i]->name = "Visitor";
    data[i]->carNum = 0;
    data[i]->limoNum = -1;
    data[i]->limo = false;
    data[i]->visNum = i;
    visitors[i]->Fork((VoidFunctionPtr)Visitor,(int)data[i]);
  }

  for (int i = 2; i <4; i ++){
    data[i]->name = "Visitor";
    data[i]->carNum = -1;
    data[i]->limoNum = 0;
    data[i]->limo = true;
    data[i]->visNum = i;
    visitors[i]->Fork((VoidFunctionPtr)Visitor,(int)data[i]);
  }

}
bool yesCars = true;
bool yesLimo = true;
int visPerVehicle = 0;

void testEverything(){
  correctTest = true;

  Thread *driver0;
  driver0 = new Thread("driver");

  Thread *driver1;
  driver1 = new Thread("driver");

  Thread *driver2;
  driver2 = new Thread("driver");

  Thread *driver3;
  driver3 = new Thread("driver");

  Thread *driver4;
  driver4 = new Thread("driver");

  Thread *driver5;
  driver5 = new Thread("driver");

  Thread *limo0;
  limo0 = new Thread("limo");

  Thread *limo1;
  limo1 = new Thread("limo");

  Thread *limo2;
  limo2 = new Thread("limo");

  Thread *valet0;
  valet0 = new Thread("valet");

  Thread *valet1;
  valet1 = new Thread("valet");

  Thread *valet2;
  valet2 = new Thread("valet");

  Thread *tickettaker;
  tickettaker = new Thread("ticket taker");

  Thread** visitors;
  visitors = new Thread* [numVis];

  Thread *vmanager;
  vmanager = new Thread("valet manager");
  

  for (int i = 0; i <numVis; i ++){
    visitors[i] = new Thread("Visitor");
  }
  
  visInfo** data;
  data = new visInfo* [numVis];

  for (int i = 0; i <numVis; i ++){
    data[i] = new visInfo;
  }

  passengers[0] = 2;
  passengers[1] = 2;
  passengers[2] = 2;
  passengers[3] = 2;
  passengers[4] = 2;
  passengers[5] = 2;

  limoPassengers[0] = 3;
  limoPassengers[1] = 3;
  limoPassengers[2] = 3;

  vmanager->Fork((VoidFunctionPtr)valetManager,0);
  valet0->Fork((VoidFunctionPtr)Valet,0);
  valet1->Fork((VoidFunctionPtr)Valet,1);
  valet2->Fork((VoidFunctionPtr)Valet,2);
  tickettaker->Fork((VoidFunctionPtr)TicketTaker,0);
  driver0->Fork((VoidFunctionPtr)Driver,0);
  driver1->Fork((VoidFunctionPtr)Driver,1);
  driver2->Fork((VoidFunctionPtr)Driver,2);
  driver3->Fork((VoidFunctionPtr)Driver,3);
  driver4->Fork((VoidFunctionPtr)Driver,4);
  driver5->Fork((VoidFunctionPtr)Driver,5);
  limo0->Fork((VoidFunctionPtr)limoDriver,0);
  limo1->Fork((VoidFunctionPtr)limoDriver,1);
  limo2->Fork((VoidFunctionPtr)limoDriver,2);

  for (int i = 0; i <2; i ++){
    data[i]->name = "Visitor";
    data[i]->carNum = 0;
    data[i]->limoNum = -1;
    data[i]->limo = false;
    data[i]->visNum = i;
    visitors[i]->Fork((VoidFunctionPtr)Visitor,(int)data[i]);
  }
  for (int i = 2; i <4; i ++){
    data[i]->name = "Visitor";
    data[i]->carNum = 1;
    data[i]->limoNum = -1;
    data[i]->limo = false;
    data[i]->visNum = i;
    visitors[i]->Fork((VoidFunctionPtr)Visitor,(int)data[i]);
  }
  for (int i = 4; i <6; i ++){
    data[i]->name = "Visitor";
    data[i]->carNum = 2;
    data[i]->limoNum = -1;
    data[i]->limo = false;
    data[i]->visNum = i;
    visitors[i]->Fork((VoidFunctionPtr)Visitor,(int)data[i]);
  }
  for (int i = 6; i <8; i ++){
    data[i]->name = "Visitor";
    data[i]->carNum = 3;
    data[i]->limoNum = -1;
    data[i]->limo = false;
    data[i]->visNum = i;
    visitors[i]->Fork((VoidFunctionPtr)Visitor,(int)data[i]);
  }
  for (int i = 8; i <10; i ++){
    data[i]->name = "Visitor";
    data[i]->carNum = 4;
    data[i]->limoNum = -1;
    data[i]->limo = false;
    data[i]->visNum = i;
    visitors[i]->Fork((VoidFunctionPtr)Visitor,(int)data[i]);
  }
  for (int i = 10; i <12; i ++){
    data[i]->name = "Visitor";
    data[i]->carNum = 5;
    data[i]->limoNum = -1;
    data[i]->limo = false;
    data[i]->visNum = i;
    visitors[i]->Fork((VoidFunctionPtr)Visitor,(int)data[i]);
  }
   
  for (int i = 12; i <15; i ++){
    data[i]->name = "Visitor";
    data[i]->carNum = -1;
    data[i]->limoNum = 0;
    data[i]->limo = true;
    data[i]->visNum = i;
    visitors[i]->Fork((VoidFunctionPtr)Visitor,(int)data[i]);
  }
  for (int i = 15; i <18; i ++){
    data[i]->name = "Visitor";
    data[i]->carNum = -1;
    data[i]->limoNum = 1;
    data[i]->limo = true;
    data[i]->visNum = i;
    visitors[i]->Fork((VoidFunctionPtr)Visitor,(int)data[i]);
  }
  for (int i = 18; i <21; i ++){
    data[i]->name = "Visitor";
    data[i]->carNum = -1;
    data[i]->limoNum = 2;
    data[i]->limo = true;
    data[i]->visNum = i;
    visitors[i]->Fork((VoidFunctionPtr)Visitor,(int)data[i]);
  }
}
  /*
  correctTest = true;
  int count = 0;

  Thread** drivers;
  drivers = new Thread* [numberOfCars];

  for (int i = 0; i <numberOfCars;i++)
    drivers[i] = new Thread("driver");

  Thread** limoDrivers;
  limoDrivers = new Thread* [numberLimo];
  
  for (int i = 0; i <numberLimo;i++)
    limoDrivers[i] = new Thread("Limo Drivers");

  Thread** valets;
  valets = new Thread* [numValet];

  for (int i = 0; i<numValet; i++)
    valets[i] = new Thread ("Valet");

  Thread** visitors;
  visitors = new Thread* [numVis];

  for (int i = 0; i<numVis; i++)
    visitors[i] = new Thread ("Visitor");

  visInfo** data;
  data = new visInfo* [numVis];

  for (int i = 0; i <numVis; i ++)
    data[i] = new visInfo;

  for (int i = 0; i < numberOfCars; i++)
    passengers[i] = visPerVehicle;

  for (int i = 0; i < numberLimo; i++)
    limoPassengers[i] = visPerVehicle;

  
  Thread* ticketTaker;
  ticketTaker = new Thread ("Ticket Taker");

  Thread* valetManager;
  valetManager = new Thread ("Valet Manager");

  for (int i = 0; i <numValet;i++)
    valets[i]->Fork((VoidFunctionPtr)Valet,i);
  
  for (int i = 0; i <numberOfCars;i++)
    drivers[i]->Fork((VoidFunctionPtr)Driver,i);
  
  for (int i = 0; i <numberLimo;i++)
   limoDrivers[i]->Fork((VoidFunctionPtr)limoDriver,i);
  
  ticketTaker->Fork((VoidFunctionPtr)TicketTaker,0);
  //valetManager->Fork((VoidFunctionPtr)valetManager,0);
  
  for (int j = 0; j <numberOfCars; j++){
    for (int i = 0; i <visPerVehicle; i ++){
      data[i]->name = "Visitor";
      data[i]->carNum = j;
      data[i]->limoNum = -1;
      data[i]->limo = false;
      data[i]->visNum = count;
      count++;
      visitors[i]->Fork((VoidFunctionPtr)Visitor,(int)data[i]);
    }
  }
  
  for (int j = 0; j <numberLimo; j++){
    for (int i = 0; i <visPerVehicle; i ++){
      data[count]->name = "Visitor";
      data[count]->carNum = -1;
      data[count]->limoNum = j;
      data[count]->limo = true;
      data[count]->visNum = count;
      visitors[count]->Fork((VoidFunctionPtr)Visitor,(int)data[count]);
      count++;
    }
  }
  */


void Problem2(){

  int input = -1;
  /*
  cout<<"1. 1 Car with visitors and 1 Valet and a Ticket Taker"<<endl;
  cout<<"2. 1 Car 5 Limos and 2 valets with no visitors"<<endl;
  cout<<"3. 10 Cars and 3 valets with no visitors"<<endl;
  cout<<"4. 10 Limos and 5 valets and a valet manager"<<endl;
  cout<<"5. 3 Cars 3 Limos 2 visitors in car 0 and 2 visitors in Limo 0"<<endl;
  cout<<"6. 1 car 5 Limos 3 Valets and a Valet manager, no Visitors"<<endl;
  cout<<"7. 1 Car 2 limos and 2 valets, 4 visitors in the car and 2 in each limo"<<endl;
  cout<<"8. 1 Car 2 limos and 2 valets, 4 visitors in the car and 2 in each limo and also a ticket taker"<<endl;
  cout<<"9. 1 Car 1 limo 2 valet 1 visitor in the car and a ticket taker"<<endl;
  cout<<"10. 1 car 1 limo 2 valets 2 visitors in the car and 2 in the limo and a ticket taker"<<endl;
  */
  cout<<"Please see WRITEUP.txt for test details"<<endl;
  cout<<"Please enter a test number 1 - 11: ";
  cin>>input;

  if (input == 1){
    numberOfCars = 1;
    numberLimo = 1; //cannot be zero but no limos will be started
    numTT = 1;
    numValet = 2;
    numVis = 2;
  }else if (input == 2){
    numberOfCars = 1;
    numberLimo = 5;
    numTT = 0;
    numValet = 2;
    numVis = 0;
  }else if (input == 3){
    numberOfCars = 10;
    numberLimo = 1; //cannot be zero but no limos will be started
    numTT = 1;
    numValet = 3;
    numVis = 0;
  }else if (input == 4){
    numberOfCars = 1;//cannot be zero but no cars will be started
    numberLimo = 10;
    numTT = 0;
    numValet = 5;
    numVis = 0;
    manager = true;
  }else if (input == 5){
    numberOfCars = 3;
    numberLimo = 2;
    numTT = 0;
    numValet = 0;
    numVis = 4;
  }else if (input == 6){
    numberOfCars = 1;
    numberLimo = 5;
    numTT = 0;
    numValet = 3;
    numVis = 0;
    manager = true;
  }else if (input == 7){
    numberOfCars = 1;
    numberLimo = 2;
    numTT = 0;
    numValet = 2;
    numVis = 8;
  }else if (input == 8){
    numberOfCars = 1;
    numberLimo = 2;
    numTT = 1;
    numValet = 2;
    numVis = 8;
  }else if (input == 9){
    numberOfCars = 1;
    numberLimo = 1;
    numTT = 1;
    numValet = 2;
    numVis = 1;
  }else if (input == 10){
    numberOfCars = 1;
    numberLimo = 1;
    numTT = 1;
    numValet = 2;
    numVis = 4;
  }else if (input == 11){
    cout<<"This test will run with the following data:"<<endl;
    cout<<"6 Cars with 2 Visitors each"<<endl;
    cout<<"2 Limos with 3 Visitors each"<<endl;
    cout<<"3 Valets"<<endl;
    cout<<"1 Ticket Taker"<<endl;
    cout<<"1 Valet Manager"<<endl;

    numberOfCars = 6;
    numberLimo = 3;
    numValet = 3;
    numTT = 1;
    manager = true;
    numVis = 21;
    /*
    string  query;
    numberOfCars = 1;
    numberLimo = 1;
    cout<<"Do you want Cars y or n: ";
    cin>>query;
    
    if (query == "y" || query == "yes"){
      cout<<"Entering 0 will be translated to a 1"<<endl;
      cout<<"How many Cars do you want: ";
      cin>>numberOfCars;
    }
    
    cout<<"Do you want Limos y or n: ";
    cin>>query;

    if (query == "y" || query == "yes"){
      cout<<"Entering 0 will be translated to a 1"<<endl;
      cout<<"How many Limos do you want: ";
      cin>>numberLimo;
    }
    
    cout<<"How many Valets do you want: ";
    cin>>numValet;

    cout<<"How many Visitors per car do you want *Each car or limo will have the same number of Visitors*: ";
    cin>>visPerVehicle;

    if (numberOfCars == 0){
      numberOfCars = 1;
    }
    
    if (numberLimo == 0){
      numberLimo = 1;
    }
    numVis = visPerVehicle * (numberOfCars + numberLimo);
    */
  }

  //allocation of memory based on test number defined above
  passengers = new int[numberOfCars];
  limoPassengers = new int[numberLimo];

  outOfCar = new int[numberOfCars];
  limoOutOfCar = new int[numberLimo];
  
  for (int i = 0; i<numberOfCars; i++)
    passengers[0] = 0;
  
  for (int i = 0; i<numberLimo +1; i++)
    limoPassengers[0] = 0;

  for (int i = 0; i<numberOfCars; i++)
    outOfCar[0] = 0;

  for (int i = 0; i<numberLimo+1; i++)
    limoOutOfCar[0] = 0;

  //allocating memory for car locks
  carLock = new Lock* [numberOfCars];
  for(int i = 0; i<numberOfCars; i++)
    carLock[i] = new Lock("test");

  //allocating memory for limo locks
  limoLock = new Lock* [numberLimo];
  for(int i = 0; i<(numberLimo); i++){
    limoLock[i] = new Lock ("limo Lock");
  }
  
  parkingLock1 = new Lock("parking Lock");

  lineLock = new Lock("line lock");

  breakLock = new Lock("break lock");

  driverWaitingCV = new Condition* [numberOfCars];
  for(int i = 0; i<numberOfCars; i++) 
    driverWaitingCV[i] = new Condition("driver waiting");

  visitorExit = new Condition* [numberOfCars];
  for(int i = 0; i<numberOfCars; i++) 
    visitorExit[i] = new Condition("Visitor can exit");

  visitorLimoExit = new Condition* [numberLimo];
  for(int i = 0; i<numberLimo; i++) 
    visitorLimoExit[i] = new Condition("Visitor can exit");

  readyToLeave = new Condition* [numberOfCars];
  for(int i = 0; i<numberOfCars; i++) 
    readyToLeave[i] = new Condition("ready to leave");

  limoReadyToLeave = new Condition* [numberLimo];
  for(int i = 0; i<numberLimo; i++) 
    limoReadyToLeave[i] = new Condition("ready to leave");


  waitToLeave = new Condition* [numberLimo];
  for(int i = 0; i<numberOfCars; i++) 
    waitToLeave[i] = new Condition("waiting to leave");

  limoWaitToLeave = new Condition* [numberLimo];
  for(int i = 0; i<numberLimo; i++) 
    limoWaitToLeave[i] = new Condition("waiting to leave");

  waitExit = new Condition* [numberOfCars];
  for(int i = 0; i<numberOfCars; i++) 
    waitExit[i] = new Condition("waiting to drive off");

  limoWaitExit = new Condition* [numberLimo];
  for(int i = 0; i<numberLimo; i++) 
    limoWaitExit[i] = new Condition("waiting to drive off");

  canLeave = new Condition* [numberOfCars];
  for(int i = 0; i<numberOfCars; i++) 
    canLeave[i] = new Condition("can leave the museum");

  limoCanLeave = new Condition* [numberLimo];
  for(int i = 0; i<numberLimo; i++) 
    limoCanLeave[i] = new Condition("can leave the museum");

  leaving = new Condition ("leaving");
  limoLeaving = new Condition ("leaving");

  readyToPark = new Condition ("ready to park");
  limoReadyToPark = new Condition("limo ready to park");

  limoWaitingCV = new Condition* [numberLimo];
  for(int i = 0; i<numberLimo; i++) 
    limoWaitingCV[i] = new Condition("driver waiting");
  
  hasKeys = new Condition* [numberOfCars];
  for(int i = 0; i<numberOfCars; i++) 
    hasKeys[i] = new Condition ("waiting for keys");

  limoHasKeys = new Condition* [numberLimo];
  for(int i = 0; i<numberLimo; i++) 
    limoHasKeys[i] = new Condition ("waiting for Limo keys");

  hasToken = new Condition* [numberOfCars];
  for(int i = 0; i<numberOfCars; i++) 
    hasToken[i] = new Condition("waiting for parking token");

  limoHasToken = new Condition* [numberLimo];
  for(int i = 0; i<numberLimo; i++) 
    limoHasToken[i] = new Condition("waiting for Limo parking token");

  leaveToken = new Condition* [numberOfCars];
  for(int i = 0; i<numberOfCars; i++) 
    leaveToken[i] = new Condition("waiting for token so car can leave");

  limoLeaveToken = new Condition* [numberLimo];
  for(int i = 0; i<(numberLimo); i++) 
    limoLeaveToken[i] = new Condition("waiting for token so car can leave");

  Tip = new Condition ("Waiting for a tip");

  limoTip = new Condition* [numberLimo];
  for(int i = 0; i<(numberLimo ); i++) 
    limoTip[i] = new Condition ("Waiting for a tip");
  
  ticketLine = new Condition("wait for ticket accpetance");

  waitOnCustomers = new Condition("wait for customers");

  waitForCars = new Condition("wait for cars");

  waitForBreak = new Condition("wait for Break");

  waitCarLeaving = new Condition* [numberOfCars];
  for(int i = 0; i<numberOfCars; i++) 
    waitCarLeaving[i] = new Condition("wait to leave");

  waitLimoLeaving = new Condition* [numberLimo];
  for(int i = 0; i<(numberLimo ); i++) 
    waitLimoLeaving[i] = new Condition("wait to leave");

  managerWaiting = new Condition("go on break");
  backRoom = new Condition("In the back");

  carnumbersArrive = new List;
  carnumbersLeave = new List;
  limoListToPark = new List;
  limoListToLeave = new List;

  switch (input){
  case (1): test1();
    break;
  case (2): test2();
    break;
  case (3): test3();
    break;
  case (4): test4();
    break;
  case (5): test5();
    break;
  case (6): test6();
    break;
  case (7): test7();
    break;
  case (8): test8();
    break;
  case (9): test9();
    break;
  case (10): test10();
    break;
  case (11): testEverything();
    break;
  default: cout<<"No corresponding test to that number!!!!!!!"<<endl;
  }

}
